/**
 * 
 */
package org.t2.backstage.module.player.service;

import java.sql.SQLSyntaxErrorException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.banish.sql.core.dao.Dao;
import org.banish.sql.core.datasource.IDataSource;
import org.banish.sql.core.util.QuerySet;
import org.gaming.ruler.schedule.LoopingTask;
import org.gaming.service.service.AbstractService;
import org.gaming.tool.DateTimeUtil;
import org.gaming.tool.ListMapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.t2.backstage.module.gameserver.model.GameServer;
import org.t2.backstage.module.gameserver.service.DataBaseManager;
import org.t2.backstage.module.gameserver.service.GameServerService;
import org.t2.backstage.module.player.model.PlayerLTV;
import org.t2.backstage.module.system.model.SystemCounter;
import org.t2.backstage.module.system.service.SystemCounterService;

import sh.t2.share.module.player.log.PlayerCreateLog;
import sh.t2.share.module.player.log.PlayerRechargeLog;

/**
 * @author YY
 * 记创号当日的玩家数量为P，
 * 记创号当日至当前日期该批用户的总充值额为C-n，n表示距离创号当日的天数，n=0表示创号当前
 * 则LTV-n = C-n / P
 */
@Service
public class PlayerLTVService extends AbstractService<PlayerLTV> {

	@Autowired
	private GameServerService gameServerService;
	@Autowired
	private DataBaseManager dataBaseManager;
	@Autowired
	private SystemCounterService systemCounterService;
	
	public void insertUpdate(List<PlayerLTV> ltvs) {
		this.repository().getBaseDao().insertUpdate(ltvs);
	}
	
	@LoopingTask(name = "PlayerTimer-LTV统计", spaceTime = DateTimeUtil.ONE_SECOND_MILLIS * 10, execGroup = 2)
	private void runInSchedule() {
		SystemCounter systemCounter = systemCounterService.instance();
		if(DateTimeUtil.currMillis() < systemCounter.getLtvTime()) {
			return;
		}
		//12小时刷新一次
		systemCounter.setLtvTime(DateTimeUtil.currMillis() + DateTimeUtil.ONE_HOUR_MILLIS * 12);
		systemCounterService.update(systemCounter);
		
		countLTV(DateTimeUtil.todayZeroMillis());
	}
	
	
	public void countLTV(long dateTimeMillis) {
		//今天统计的是昨天的数据
		dateTimeMillis = dateTimeMillis - DateTimeUtil.ONE_DAY_MILLIS;
		
		String currYMD = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, dateTimeMillis);
		logger.info("开始{}的LTV统计", currYMD);
		
		for(GameServer gameServer : gameServerService.getEntityList(0)) {
			countLTV(gameServer, dateTimeMillis);
		}
		logger.info("完成{}的LTV统计", currYMD);
	}
	
	public List<PlayerLTV> queryLTV(QuerySet query) {
		return this.repository().getBaseDao().queryListWhere(query.getWhere(), query.getParams());
	}
	
	/**
	 * 
	 * @param channel
	 * @param serverUid
	 * @param currYMD 格式yyyy-MM-dd
	 * @param nextYMD 格式yyyy-MM-dd
	 * @return
	 */
	public void countLTV(GameServer gameServer, long currMillis) {
		int countDate = Integer.parseInt(DateTimeUtil.formatMillis(DateTimeUtil.YYYYMMDD, currMillis));
		logger.info("进行服务器{}-{}日期{}的LTV统计", gameServer.getId(), gameServer.getName(), countDate);
		
		try {
			IDataSource dataBase = dataBaseManager.getLogDb(gameServer.getId());
			if(dataBase == null) {
				logger.error("进行服务器{}-{}的LTV统计中，未定义数据库连接信息", gameServer.getId(), gameServer.getName());
				return;
			}
			//1、统计创号人数
			//<渠道，注册日志>
			Map<Long, List<PlayerCreateLog>> channelCreateMap = queryCreateLog(dataBase, currMillis);
			//2、统计充值金额
			//<渠道，充值日志>
			Map<Long, List<PlayerRechargeLog>> channelRechargeMap = queryRechargeLog(dataBase, currMillis);
			
			Set<Long> channelIds = new HashSet<>();
			channelIds.addAll(channelCreateMap.keySet());
			channelIds.addAll(channelRechargeMap.keySet());
			
			Map<String, PlayerLTV> resultMap = new HashMap<>();
			for(long channelId : channelIds) {
				List<PlayerCreateLog> createLogs = channelCreateMap.get(channelId);
				int playerCount = createLogs == null ? 0 : createLogs.size();
				
				List<PlayerRechargeLog> rechargeLogs = channelRechargeMap.getOrDefault(channelId, Collections.emptyList());
				
				for(PlayerRechargeLog rechargeLog : rechargeLogs) {
					int bornDate = rechargeLog.getBornDate();
					int dayCount = rechargeLog.getRechargeDate() - rechargeLog.getBornDate();
					
					String key = channelId + "_" + bornDate + "_" + dayCount;
					
					PlayerLTV playerLTV = resultMap.get(key);
					if(playerLTV == null) {
						playerLTV = new PlayerLTV();
						playerLTV.setChannelId(channelId);
						playerLTV.setServerUid(gameServer.getId());
						playerLTV.setBorn(bornDate);
						playerLTV.setDayCount(dayCount);
						playerLTV.setPlayerCount(playerCount);
						resultMap.put(key, playerLTV);
					}
					playerLTV.setMoney(playerLTV.getMoney() + rechargeLog.getMoney());
				}
				
				String currDateKey = channelId + "_" + countDate + "_0";
				if(!resultMap.containsKey(currDateKey)) {
					PlayerLTV playerLTV = new PlayerLTV();
					playerLTV.setChannelId(channelId);
					playerLTV.setServerUid(gameServer.getId());
					playerLTV.setBorn(countDate);
					playerLTV.setDayCount(0);
					playerLTV.setMoney(0);
					playerLTV.setPlayerCount(playerCount);
					resultMap.put(currDateKey, playerLTV);
				}
			}
			this.insertUpdate(new ArrayList<>(resultMap.values()));
		} catch (Exception e) {
			if(e.getCause() instanceof SQLSyntaxErrorException) {
				logger.error("统计LTV发生异常，{}", e.getCause().getMessage());
			} else {
				logger.error("统计LTV发生异常", e);
			}
		}
	}
	
	/**
	 * 统计某个时间之后的创号人数
	 * @param dataBase
	 * @param channelId
	 * @param currMillis
	 * @return
	 */
	public Map<Long, List<PlayerCreateLog>> queryCreateLog(IDataSource dataBase, long dateTimeMillis) {
		//也可以用这样的SQL来查
//		String countCreateSql = "SELECT DATE_FORMAT(born_time, '%Y%m%d') AS bornDate, count(1) AS playerCount "
//				+ "FROM player_create_log WHERE channel_id = ? AND born_time >= ? GROUP BY DATE_FORMAT(born_time, '%Y%m%d')";
		String currYMD = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, dateTimeMillis);
		long nextDateTime = dateTimeMillis + DateTimeUtil.ONE_DAY_MILLIS;
		String nextYMD = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, nextDateTime);
		
		String playerCreateLogSql = "select * from player_create_log ";
		QuerySet querySet = new QuerySet();
		querySet.addCondition("born_time >= ?", currYMD);
		querySet.addCondition("born_time < ?", nextYMD);
		querySet.formWhere();
		String sql = playerCreateLogSql + querySet.getWhere();
		
		List<PlayerCreateLog> logs = Dao.queryAliasObjects(dataBase, PlayerCreateLog.class, sql, querySet.getParams());
		return ListMapUtil.fillListMap(logs, PlayerCreateLog::getChannelId);
	}
	
	/**
	 * 统计某一天的充值金额
	 * @param dataBase
	 * @param channelId
	 * @param currMillis
	 * @return
	 */
	public Map<Long, List<PlayerRechargeLog>> queryRechargeLog(IDataSource dataBase, long dateTimeMillis) {
//		String countRechargeSql = "SELECT DATE_FORMAT(born_time, '%Y%m%d') AS bornDate, DATEDIFF(recharge_time, born_time) AS dayCount, sum(money) AS money " + 
//				"FROM player_recharge_log WHERE channel_id = ? AND recharge_time >= ? AND recharge_time < ? GROUP BY DATE_FORMAT(born_time, '%Y%m%d'), DATEDIFF(recharge_time, born_time)";
		
		String currYMD = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, dateTimeMillis);
		long nextDateTime = dateTimeMillis + DateTimeUtil.ONE_DAY_MILLIS;
		String nextYMD = DateTimeUtil.formatMillis(DateTimeUtil.YYYY_MM_DD, nextDateTime);
		
		
		String playerRechargeLogSql = "select * from player_recharge_log ";
		QuerySet querySet = new QuerySet();
		querySet.addCondition("recharge_time >= ?", currYMD);
		querySet.addCondition("recharge_time < ?", nextYMD);
		querySet.formWhere();
		String sql = playerRechargeLogSql + querySet.getWhere();
		List<PlayerRechargeLog> logs = Dao.queryAliasObjects(dataBase, PlayerRechargeLog.class, sql, querySet.getParams());
		return ListMapUtil.fillListMap(logs, PlayerRechargeLog::getChannelId);
		
		
		//<20240401_0, RechargeCount> <创号日期_充值时间距离创号的天数>
//		Map<String, RechargeCount> countResult = new HashMap<>();
//		for(PlayerRechargeLog log : logs) {
//			int bornDate = log.getBornDate();
//			int dayCount = log.getRechargeDate() - log.getBornDate();
//			
//			String key = bornDate + "_" + dayCount;
//			RechargeCount rechargeCount = countResult.get(key);
//			if(rechargeCount == null) {
//				rechargeCount = new RechargeCount();
//				rechargeCount.setBornDate(bornDate);
//				rechargeCount.setDayCount(dayCount);
//				countResult.put(key, rechargeCount);
//			}
//			rechargeCount.setMoney(rechargeCount.getMoney() + log.getMoney());
//		}
//		return countResult;
	}

	@Override
	public void mergeServer(int mergeDbZoneId) {
		//不用实现
	}
}
